package com.mutual.assistance.task.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.houbb.sensitive.word.bs.SensitiveWordBs;
import com.mutual.assistance.constant.RedisConstant;
import com.mutual.assistance.exception.BizException;
import com.mutual.assistance.exception.code.ExceptionCode;
import com.mutual.assistance.response.PageParams;
import com.mutual.assistance.response.PageResult;
import com.mutual.assistance.response.R;
import com.mutual.assistance.task.constant.StringConstant;
import com.mutual.assistance.task.converter.TaskConverterParams;
import com.mutual.assistance.task.feignclient.UserServiceClient;
import com.mutual.assistance.task.mapper.*;
import com.mutual.assistance.task.model.bo.UserMessageBO;
import com.mutual.assistance.task.model.dto.*;
import com.mutual.assistance.task.model.po.*;
import com.mutual.assistance.task.model.vo.*;
import com.mutual.assistance.task.mq.constant.MqConstant;
import com.mutual.assistance.task.service.TaskPublish;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;

import static com.mutual.assistance.constant.RedisConstant.*;
import static com.mutual.assistance.exception.code.ExceptionCode.*;
import static com.mutual.assistance.response.R.UPDATE_SUCCESS;
import static com.mutual.assistance.task.constant.StringConstant.*;
import static com.mutual.assistance.task.constant.TaskRedisConstant.*;
import static com.mutual.assistance.task.mq.constant.MqConstant.*;

/**
 * @author chenyuxin
 * @version 1.0
 * @description 发布任务实现类
 * @date 2023/4/28 16:17
 */
@Service
@Slf4j
@SuppressWarnings("all")
public class TaskPublishImpl implements TaskPublish {

    @Resource
    private TaskPublish taskPublish;

    @Resource
    private TaskPublishPreMapper taskPublishPreMapper;

    @Resource
    private TaskConverterParams taskConverterParams;

    @Resource
    private UserServiceClient userServiceClient;

    @Resource
    private RabbitTemplate rabbitTemplate;

    @Resource
    private Executor asyncPromiseExecutor;

    @Resource
    private TaskAuditMapper taskAuditMapper;

    @Resource
    private TaskPublishMapper taskPublishMapper;

    @Resource
    private TaskPublishHistoryMapper taskPublishHistoryMapper;

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private TaskAppraiseMapper taskAppraiseMapper;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private CommentMapper commentMapper;

    @Resource
    private SensitiveWordBs sensitiveWordBs;

    @Override
    @GlobalTransactional
    public void createTask(CreateTaskParamsVO createTaskParamsVO, String publisher) {

        // 判断是否有相同的任务
        checkTaskIsExisted(createTaskParamsVO.getTitle(), createTaskParamsVO.getContent(), publisher);

        checkTaskPublishTime(createTaskParamsVO);

        convertTas(createTaskParamsVO);

        Integer credit = createTaskParamsVO.getCredit();

        if (credit > 0) {
            // 调用user服务扣减积分
            R<String> stringR = userServiceClient.subCredit(publisher, credit);
            if (!stringR.getMsg().equals(UPDATE_SUCCESS)) {
                throw new BizException(stringR.getCode(), stringR.getMsg());
            }
        }

        // 创建预发布表
        createPreTask(createTaskParamsVO, publisher);

        String message = "尊敬的用户您的任务" + createTaskParamsVO.getTitle() + PREPUBLISH_SUCCESS;

        log.info("发布消息给用户：{}", publisher);
        receiveMessageToUser(message, publisher);

    }

    private static void checkTaskPublishTime(CreateTaskParamsVO createTaskParamsVO) {
        LocalDateTime taskStartTime = createTaskParamsVO.getTaskStartTime();
        log.info("获取到开始时间：{}", taskStartTime);

        LocalDateTime now = LocalDateTime.now();

        LocalDateTime taskEndTime = createTaskParamsVO.getTaskEndTime();
        log.info("获取到结束时间：{}", taskEndTime);

        if (taskEndTime.isBefore(taskStartTime) || taskStartTime.isBefore(now) || taskEndTime.isBefore(now)) {
            log.error("结束的时间应该在开始时间之后");
            throw new BizException(TASK_TIME_ERROR.getCode(), TASK_TIME_ERROR.getMsg());
        }
    }

    private static void convertTas(CreateTaskParamsVO createTaskParamsVO) {
        List<String> tagList = Arrays.asList("日用品", "二手书", "跑腿", "求助", "求大神指导", "吃瓜", "二手交易", "太难了", "泰酷啦", "又懂又懂", "入股不亏",
                "秀儿，是你吗", "干就完事了", "我太南了", "内牛满面", "破防", "企业级理解", "顶级理解", "真香", "元芳，你怎么看？"
                , "五块钱以下的活动别叫我", "躺着也中枪", "上头", "slb");
        String tags = createTaskParamsVO.getTags();
        log.info("获取到标签：{}", tags);
        Set<Integer> object = JSON.parseObject(tags, new TypeReference<Set<Integer>>() {
        });
        StringJoiner stringJoiner = new StringJoiner(",");
        for (Integer integer : object) {
            stringJoiner.add(tagList.get(integer));
        }
        createTaskParamsVO.setTags(stringJoiner.toString());
    }

    private void receiveMessageToUser(String message, String publisher) {
        asyncPromiseExecutor.execute(() -> {
            UserMessageBO userMessageBO = new UserMessageBO();
            userMessageBO.setType(SYSTEM_NOTICE);
            userMessageBO.setMessage(message);
            userMessageBO.setUsername(publisher);
            sendMessageToUser(userMessageBO);
        });
    }

    @Override
    public TaskPrePublishPersonDTO getOnePreTask(TaskParamsVO revokePreTaskParamsVO) {
        log.info("获取到前端传入参数：{}", revokePreTaskParamsVO);
        TaskPublishPrePO task = getTaskById(revokePreTaskParamsVO.getTaskId(), revokePreTaskParamsVO.getPublisher(), true);
        log.info("获取到数据库参数：{}", task);
        TaskPrePublishPersonDTO dto = taskConverterParams.taskPublishPrePO2TaskPrePublishPersonDTO(task);
        log.info("获取到转换参数：{}", dto);
        return dto;
    }

    @Override
    public PageResult<TaskPrePublishDTO> getAllTaskToAudit(PageParams pageParams, AuditPrePublishTask auditPrePublishTask) {
        log.info("获取到前端传入参数：{}", auditPrePublishTask);
        LambdaQueryWrapper<TaskPublishPrePO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TaskPublishPrePO::getStatus, StringConstant.UNAUDITED);

        Long taskId = auditPrePublishTask.getId();
        log.info("获取到任务id：{}", taskId);
        queryWrapper.eq(taskId != null, TaskPublishPrePO::getId, taskId);

        String publisher = auditPrePublishTask.getPublisher();
        log.info("获取到发布者id：{}", publisher);
        queryWrapper.eq(publisher != null, TaskPublishPrePO::getPublisher, publisher);

        String type = auditPrePublishTask.getType();
        log.info("获取任务类型：{}", type);
        queryWrapper.eq(type != null, TaskPublishPrePO::getType, type);

        String title = auditPrePublishTask.getTitle();
        log.info("获取到标题：{}", title);
        queryWrapper.eq(title != null, TaskPublishPrePO::getTitle, title);

        Integer credit = auditPrePublishTask.getCredit();
        log.info("获取到积分：{}", credit);
        queryWrapper.eq(credit != null, TaskPublishPrePO::getCredit, credit);

        Page<TaskPublishPrePO> page = new Page<>(pageParams.getPageNo(), pageParams.getPageSize());
        Page<TaskPublishPrePO> pageResult = taskPublishPreMapper.selectPage(page, queryWrapper);
        log.info("获取到数据分页参数：{}", pageResult);
        List<TaskPublishPrePO> records = pageResult.getRecords();
        log.info("获取到集合：{}", records);
        List<TaskPrePublishDTO> taskPrePublishDTOS = new ArrayList<>();
        for (TaskPublishPrePO record : records) {
            TaskPrePublishDTO prePublishDTO = taskConverterParams.taskPublishPrePO2TaskPrePublishDTO(record);
            log.info("获取到任务信息：{}", prePublishDTO);
            UserDTO userDTO = getUserDTO(record.getPublisher());
            prePublishDTO.setPublisher(userDTO);
            taskPrePublishDTOS.add(prePublishDTO);
        }
        log.info("获取到转换后参数：{}", taskPrePublishDTOS);
        long total = pageResult.getTotal();
        return new PageResult<>(taskPrePublishDTOS, total, pageParams.getPageNo(), pageParams.getPageSize());
    }

    @Override
    public PageResult<TaskPrePublishDTO> getAllTaskToAuditCache(PageParams pageParams) {
        String data = stringRedisTemplate.opsForValue().get(PRE_PUBLISH_TASK_CACHE_AUDIT);
        if (data != null) {
            return JSON.parseObject(data, new TypeReference<PageResult<TaskPrePublishDTO>>() {
            });
        }

        RLock lock = redissonClient.getLock(PRE_TASK_AUDIT_REDISSON_LOCK);
        lock.lock();

        try {
            log.info("获取到前端传入参数");
            LambdaQueryWrapper<TaskPublishPrePO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(TaskPublishPrePO::getStatus, StringConstant.UNAUDITED);
            Page<TaskPublishPrePO> page = new Page<>(pageParams.getPageNo(), pageParams.getPageSize());
            Page<TaskPublishPrePO> pageResult = taskPublishPreMapper.selectPage(page, queryWrapper);
            log.info("获取到数据分页参数：{}", pageResult);
            List<TaskPublishPrePO> records = pageResult.getRecords();
            log.info("获取到预发布集合：{}", records);
            List<TaskPrePublishDTO> taskPrePublishDTOS = new ArrayList<>();
            for (TaskPublishPrePO record : records) {
                TaskPrePublishDTO prePublishDTO = taskConverterParams.taskPublishPrePO2TaskPrePublishDTO(record);
                UserDTO userDTO = getUserDTO(record.getPublisher());
                prePublishDTO.setPublisher(userDTO);
                taskPrePublishDTOS.add(prePublishDTO);
            }
            long total = pageResult.getTotal();
            PageResult<TaskPrePublishDTO> result = new PageResult<>(taskPrePublishDTOS, total,
                    pageParams.getPageNo(), pageParams.getPageSize());
            stringRedisTemplate.opsForValue().set(PRE_PUBLISH_TASK_CACHE_AUDIT, JSON.toJSONString(result), CACHE_NULL_TTL, TimeUnit.MINUTES);
            return result;
        } finally {
            lock.unlock();
        }
    }

    @Override
    @GlobalTransactional
    public void revokeTask(TaskParamsVO revokeTaskParamsVO) {
        log.info("获取到前端传入字段：{}", revokeTaskParamsVO);
        String publisher = revokeTaskParamsVO.getPublisher();
        String taskId = revokeTaskParamsVO.getTaskId();

        TaskPublishPO taskPublishPO = getAlreadyTaskById(taskId, publisher);
        log.info("获取到发布表任务：{}", taskPublishPO);

        String status = taskPublishPO.getStatus();
        log.info("获取到发布表状态：{}", status);

        LocalDateTime taskEndTime = taskPublishPO.getTaskEndTime();
        log.info("获取到任务结束时间：{}", taskEndTime);

        LocalDateTime now = LocalDateTime.now();
        log.info("获取到现在的时间：{}", now);

        if (USER_TO_DO.equals(status) && now.isBefore(taskEndTime)) {
            log.error("不能再删除已经被接收的任务");
            throw new BizException(RECEIVED_TASK.getCode(), RECEIVED_TASK.getMsg() + " taskId：" + taskId);
        }

        if (TASK_INCOMPLETE.equals(status)) {
            log.info("开始插入历史表");
            taskPublishPO.setOfflineDate(LocalDateTime.now());
            insertTaskHistory(taskPublishPO);
        }

        deletePublishTask(taskId, publisher);

        // 根据任务id和用户id获取预发布表任务
        TaskPublishPrePO taskPublishPrePO = getTaskById(taskId, publisher, false);
        if (taskPublishPrePO == null) {
            log.info("预发布任务为空");
            return;
        }
        log.info("获取到要删除的预发布信息：{}", taskPublishPrePO);
        deletePreTask(taskId);

        log.info("开始回滚用户积分");
        rollBackCredit(publisher, taskPublishPO.getCredit());
    }

    private void deletePublishTask(String taskId, String publisher) {
        int delete = taskPublishMapper.delete(new LambdaQueryWrapper<TaskPublishPO>()
                .eq(TaskPublishPO::getId, taskId)
                .eq(TaskPublishPO::getPublisher, publisher)
        );
        if (delete <= 0) {
            log.error("删除发布表失败");
            throw BizException.wrap(SQL_EX.getCode(), SQL_EX.getMsg() + "  taskId：" + taskId + " 删除发布表失败");
        }
    }


    @Override
    @GlobalTransactional
    public void userDeletePreTask(TaskParamsVO taskParamsVO) {
        // 什么状态能够删除预发布表
        String publisher = taskParamsVO.getPublisher();
        log.info("获取到发布者姓名：{}", publisher);

        String taskId = taskParamsVO.getTaskId();
        log.info("获取到任务id；{}", taskId);

        // 获取预发布表内容
        TaskPublishPrePO publishPrePO = getTaskById(taskId, publisher, true);
        log.info("获取到预发布表内容：{}", publishPrePO);
        String status = publishPrePO.getStatus();
        log.info("获取到预发布状态：{}", status);

        log.info("删除预发布表");
        deletePreTask(taskId);

        if (!PUBLISHED.equals(status)) {
            log.info("开始回滚用户积分");
            rollBackCredit(publisher, publishPrePO.getCredit());
        }
    }

    private void deletePreTask(String taskId) {
        // 删除预发布表内容
        int delete = taskPublishPreMapper.deleteById(taskId);
        if (delete <= 0) {
            log.error("删除预发布表失败");
            throw BizException.wrap(SQL_EX.getCode(), SQL_EX.getMsg() + "：删除预发布表失败");
        }
    }

    @Override
    @Transactional
    public void updatePreTask(UpdatePreTaskParamsVO updatePreTaskParamsVO, String username) {
        log.info("获取到更新预发布状态：{}", updatePreTaskParamsVO);
        String taskId = updatePreTaskParamsVO.getTaskId();
        log.info("获取到用户姓名：{}，任务id：{}", username, taskId);
        getTaskById(taskId, username, true);
        // 开始判断任务是否是已经接收状态
        TaskPublishPO taskPublishPO = taskPublishMapper.selectOne(new LambdaQueryWrapper<TaskPublishPO>()
                .eq(TaskPublishPO::getId, taskId)
                .eq(TaskPublishPO::getPublisher, username)
        );
        log.info("获取到发布表信息：{}", taskPublishPO);
        if (taskPublishPO != null) {
            String status = taskPublishPO.getStatus();
            log.info("获取到发布表状态：{}", status);
            if (USER_TO_DO.equals(status)) {
                log.error("用户已经接收任务不能再进行更改");
                throw new BizException(UPDATE_PRE_TASK.getCode(), UPDATE_PRE_TASK.getMsg() + "taskId：" + taskId);
            }
        }
        TaskPublishPrePO taskPublishPrePO = taskConverterParams.
                updatePreTaskParamsVO2TaskPublishPrePO(updatePreTaskParamsVO);
        log.info("获取到数据库预发布信息：{}", taskPublishPrePO);
        taskPublishPrePO.setOfflineDate(null);
        int update = taskPublishPreMapper.update(taskPublishPrePO, new LambdaQueryWrapper<TaskPublishPrePO>()
                .eq(TaskPublishPrePO::getId, taskId)
                .eq(TaskPublishPrePO::getPublisher, username)
        );
        if (update <= 0) {
            log.error("更新预发布表失败");
            throw BizException.wrap(SQL_EX.getCode(), SQL_EX.getMsg() + "：更新预发布表失败");
        }
    }

    @Override
    @Transactional
    public void editDown(TaskParamsVO taskParamsVO) {
        String taskId = taskParamsVO.getTaskId();
        log.info("获取到任务id：{}", taskId);
        String publishId = taskParamsVO.getPublisher();
        log.info("获取到发布者id：{}", publishId);
        TaskPublishPO taskPublishPO = getAlreadyTaskById(taskId, publishId);

        // 校验状态
        String status = taskPublishPO.getStatus();
        log.info("获取到发布表状态：{}", status);
        if (USER_TO_DO.equals(status)) {
            log.error("不能下架已经被其他用户接收的任务");
            throw new BizException(INTERNAL_SERVER_ERROR.getCode(), "不能下架已经被其他用户接收的任务: " + taskId);
        }

        taskPublishPO.setStatus(REMOVAL);

        log.info("获取到转换前发布表参数：{}", taskPublishPO);
        TaskPublishPrePO taskPublishPrePO = taskConverterParams.taskPublishPO2TaskPublishPrePO(taskPublishPO);
        taskPublishPrePO.setOfflineDate(LocalDateTime.now());
        log.info("获取到转换后参数：{}", taskPublishPO);

        // 删除发布表
        int delete = taskPublishMapper.deleteById(taskPublishPO);
        if (delete <= 0) {
            log.error("删除发布表失败");
            throw BizException.wrap(SQL_EX.getCode(), SQL_EX.getMsg() + "：删除发布表失败");
        }

        // 添加获取更新
        TaskPublishPrePO publishPrePO = getTaskById(taskId, publishId, false);

        if (publishPrePO == null) {
            int insert = taskPublishPreMapper.insert(taskPublishPrePO);
            if (insert <= 0) {
                log.error("插入预发布表失败");
                throw BizException.wrap(SQL_EX.getCode(), SQL_EX.getMsg() + "：插入预发布表失败");
            }
            return;
        }

        int updateById = taskPublishPreMapper.updateById(taskPublishPrePO);
        if (updateById <= 0) {
            log.error("更新预发布表失败");
            throw BizException.wrap(SQL_EX.getCode(), SQL_EX.getMsg() + "：更新预发布表失败");
        }
    }

    @Override
    public PageResult<TaskPrePublishPersonDTO> getUserAllPreTask(PageParams pageParams, String username) {
        String data = stringRedisTemplate.opsForValue().get(PRE_PUBLISH_TASK_CACHE);
        if (data != null) {
            return JSON.parseObject(data, new TypeReference<PageResult<TaskPrePublishPersonDTO>>() {
            });
        }

        RLock lock = redissonClient.getLock(PRE_TASK_QUERY_REDISSON_LOCK);
        lock.lock();

        try {
            Page<TaskPublishPrePO> page = new Page<>(pageParams.getPageNo(), pageParams.getPageSize());

            LambdaQueryWrapper<TaskPublishPrePO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(TaskPublishPrePO::getPublisher, username);

            Page<TaskPublishPrePO> pageResult = taskPublishPreMapper.selectPage(page, queryWrapper);
            log.info("获取到数据分页参数：{}", pageResult);
            List<TaskPublishPrePO> records = pageResult.getRecords();
            log.info("获取到集合：{}", records);
            List<TaskPrePublishPersonDTO> taskPrePublishPersonDTOS = new ArrayList<>();
            for (TaskPublishPrePO record : records) {
                log.info("开始进行转换：{}", record);
                TaskPrePublishPersonDTO taskPrePublishPersonDTO = taskConverterParams.taskPublishPrePO2TaskPrePublishPersonDTO(record);
                log.info("转换结束：{}", taskPrePublishPersonDTO);
                UserDTO userDTO = getUserDTO(username);
                taskPrePublishPersonDTO.setPublisher(userDTO);
                taskPrePublishPersonDTOS.add(taskPrePublishPersonDTO);
            }
            log.info("获取到转换后参数：{}", taskPrePublishPersonDTOS);
            long total = pageResult.getTotal();

            PageResult<TaskPrePublishPersonDTO> result = new PageResult<>(taskPrePublishPersonDTOS, total,
                    pageParams.getPageNo(), pageParams.getPageSize());
            stringRedisTemplate.opsForValue().set(PRE_PUBLISH_TASK_CACHE, JSON.toJSONString(result), CACHE_TASK_TTL, TimeUnit.SECONDS);
            return result;
        } finally {
            lock.unlock();
        }
    }

    @Override
    @GlobalTransactional
    public PageResult<TaskPublishDTO> queryAllTask(PageParams pageParams, TaskFilterParamsVO taskFilterParamsVO) {
        LambdaQueryWrapper<TaskPublishPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TaskPublishPO::getStatus, PUBLISHED);

        LocalDateTime now = LocalDateTime.now();

        queryWrapper.lt(TaskPublishPO::getTaskStartTime, now);
        queryWrapper.gt(TaskPublishPO::getTaskEndTime, now);

        String taskId = taskFilterParamsVO.getTaskId();
        log.info("获取到任务id：{}", taskId);
        queryWrapper.eq(taskId != null, TaskPublishPO::getId, taskId);

        String title = taskFilterParamsVO.getTitle();
        log.info("获取到标题：{}", title);
        queryWrapper.like(title != null, TaskPublishPO::getTitle, title);

        String content = taskFilterParamsVO.getContent();
        log.info("获取到内容：{}", content);
        queryWrapper.like(content != null, TaskPublishPO::getContent, content);

        Integer credit = taskFilterParamsVO.getCredit();
        log.info("获取到积分：{}", credit);
        queryWrapper.eq(credit != null, TaskPublishPO::getCredit, credit);

        String publisher = taskFilterParamsVO.getPublisher();
        log.info("获取到发布者姓名：{}", publisher);
        queryWrapper.eq(publisher != null, TaskPublishPO::getPublisher, publisher);

        String type = taskFilterParamsVO.getType();
        log.info("获取到类型：{}", type);
        queryWrapper.eq(type != null, TaskPublishPO::getType, type);

        LocalDateTime publishTime = taskFilterParamsVO.getPublishTime();
        log.info("获取到发布时间：{}", publishTime);
        queryWrapper.eq(publishTime != null, TaskPublishPO::getPublishTime, publishTime);

        return getTaskPublishDTOPageResult(pageParams, queryWrapper, false);
    }

    @Override
    @GlobalTransactional
    public PageResult<TaskPublishDTO> queryAllTaskCache(PageParams pageParams, String type) {
        log.info("获取到分页参数：{}", pageParams);
        log.info("获取到类型：{}", type);
        String key = PUBLISH_TASK_CACHE + type + ":";
        String data = stringRedisTemplate.opsForValue().get(key);
        if (data != null) {
            log.info("获取到redis中缓存");
            return JSON.parseObject(data, new TypeReference<PageResult<TaskPublishDTO>>() {
            });
        }
        RLock lock = redissonClient.getLock(TASK_QUERY_REDISSON_LOCK);
        lock.lock();
        log.info("开始加锁");
        try {
            LambdaQueryWrapper<TaskPublishPO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(TaskPublishPO::getStatus, StringConstant.PUBLISHED);
            queryWrapper.eq(TaskPublishPO::getType, type);
            LocalDateTime now = LocalDateTime.now();
            log.info("获取到现在的时间：{}", now);
            queryWrapper.ge(TaskPublishPO::getTaskEndTime, now);
            queryWrapper.le(TaskPublishPO::getTaskStartTime, now);
            PageResult<TaskPublishDTO> result = getTaskPublishDTOPageResult(pageParams, queryWrapper, true);
            stringRedisTemplate.opsForValue().set(key, JSON.toJSONString(result), CACHE_TASK_QUEST_TTL, TimeUnit.SECONDS);
            return result;
        } finally {
            lock.unlock();
        }
    }


    @Override
    @Transactional
    public void addCommentForTask(AddTaskCommentParamsVO addTaskCommentParamsVO) {
        log.info("获取到前端响应参数：{}", addTaskCommentParamsVO);
        String taskId = addTaskCommentParamsVO.getTaskId();

        String content = addTaskCommentParamsVO.getContent();
        checkContentIsSensitive(content);

        TaskPublishPO taskPublishPO = getTaskPublishById(taskId);
        log.info("获取到发布任务信息：{}", taskPublishPO);

        checkTaskTimeIsAvailable(taskPublishPO);
        String type = taskPublishPO.getType();
        log.info("获取到任务类型");

        // 查看任务类型是否可以添加评论
        if (!QUESTIONS_AND_ANSWERS.equals(type)) {
            log.error("错误的任务类型");
            throw new BizException(UNSUPPORTED_TASK_TYPE.getCode(), UNSUPPORTED_TASK_TYPE.getMsg() + "taskId：" + taskId);
        }
        // 查看任务状态是否为可以添加
        if (!PUBLISHED.equals(taskPublishPO.getStatus())) {
            log.error("当前任务无法再接收评论");
            throw new BizException(UNABLE_ADD_COMMENT.getCode(), UNABLE_ADD_COMMENT.getMsg() + "taskId：" + taskId);
        }

        CommentPO commentPO = taskConverterParams.addTaskCommentParamsVO2CommentPO(addTaskCommentParamsVO);
        log.info("获取到转换后参数：{}", commentPO);
        int insert = commentMapper.insert(commentPO);
        log.info("更新条数：{}", insert);
        if (insert <= 0) {
            log.error("插入评论表失败");
            throw BizException.wrap(SQL_EX.getCode(), SQL_EX.getMsg() + "：插入评论表失败");
        }

    }

    private void checkContentIsSensitive(String content) {
        log.info("获取到评论内容：{}", content);
        Boolean word = sensitiveWordBs.contains(content);

        if (BooleanUtils.isTrue(word)) {
            log.error("用户的发言包含敏感词汇");
            throw new BizException(ILLEGAL_SPEECH.getCode(), ILLEGAL_SPEECH.getMsg());
        }
    }

    @Override
    @GlobalTransactional
    public void finishTask(FinishTaskVO finishTaskVO, String publisher) {
        log.info("获取到前端响应参数：{}", finishTaskVO);
        log.info("获取到发布者：{}", publisher);

        String taskId = finishTaskVO.getTaskId();
        log.info("获取到任务的id：{}", taskId);

        TaskPublishPO taskPublishPO = getAlreadyTaskById(taskId, publisher);
        log.info("获取到发布任务的信息：{}", taskPublishPO);

        checkTaskTypeAndStatus(taskId, taskPublishPO);

        TaskAppraisePO appraiseTask = getAppraiseTask(taskId, publisher);
        log.info("获取到任务的完成评论表：{}", appraiseTask);

        log.info("开始修改任务状态");
        taskPublishPO.setOfflineDate(LocalDateTime.now());
        taskPublishPO.setStatus(TASK_FINISH);

        log.info("将任务表与预发布表进行删除");
        deletePublishTask(taskId, publisher);

        TaskPublishPrePO taskPublishPrePO = getTaskById(taskId, publisher, false);
        if (taskPublishPrePO != null) {
            deletePreTask(taskId);
        }

        log.info("加入到历史表");
        insertTaskHistory(taskPublishPO);

        Integer star = finishTaskVO.getStar();
        log.info("获取到任务星级：{}", star);

        String publisherAppraise = finishTaskVO.getPublisherAppraise();
        log.info("获取到任务评论：{}", publisherAppraise);
        checkContentIsSensitive(publisherAppraise);

        updateTaskAppraise(publisherAppraise, publisher, taskId, star);

        log.info("积分转账");
        String recipient = taskPublishPO.getRecipient();
        rollBackCredit(recipient, taskPublishPO.getCredit());

        updateUserStar(recipient);

        log.info("发布消息给任务接收者");
        String messageR = MESSAGE_HEAD + taskPublishPO.getTitle() + TASK_FINISH_NOTICE_RECEIVE;
        receiveMessageToUser(messageR, recipient);

        log.info("发送消息给任务发布者");
        String messageP = MESSAGE_HEAD + taskPublishPO.getTitle() + TASK_FINISH_NOTICE_PUBLISH;
        receiveMessageToUser(messageP, publisher);
    }

    @Override
    public void deleteTaskComment(TaskCommentVO taskCommentVO) {
        log.info("获取到前端响应信息：{}", taskCommentVO);
        String taskId = taskCommentVO.getTaskId();
        String username = taskCommentVO.getUsername();
        TaskPublishPO taskPublishPO = getAlreadyTaskById(taskId, null);
        String commentId = taskCommentVO.getCommentId();

        checkTaskAndComment(taskId, username, taskPublishPO, commentId);

        int delete = commentMapper.deleteById(commentId);
        if (delete <= 0) {
            log.error("删除评论失败");
            throw new BizException(SQL_EX.getCode(), SQL_EX.getMsg() + "删除评论失败，请重新删除");
        }

    }

    private void checkTaskAndComment(String taskId, String username, TaskPublishPO taskPublishPO, String commentId) {
        if (!QUESTIONS_AND_ANSWERS.equals(taskPublishPO.getType())) {
            log.error("这不是问答类型的任务");
            throw new BizException(SUBMITTED_TYPE_INCORRECT.getCode(),
                    SUBMITTED_TYPE_INCORRECT.getMsg() + "taskId：" + taskId + " 非问答任务");
        }

        if (!PUBLISHED.equals(taskPublishPO.getStatus())) {
            log.error("任务已超期或者任务已完成");
            throw new BizException(INTERNAL_SERVER_ERROR.getCode(), "任务已超期或者任务已完成，无法在进行删除评论");
        }

        getCommentPO(taskId, username, commentId);

        log.info("校验任务是否在规定时间内");
        checkTaskTimeIsAvailable(taskPublishPO);
    }

    @Override
    public void updateComment(UpdateCommentParamsVO updateCommentParamsVO, String username) {
        log.info("获取到前端响应的参数：{}", updateCommentParamsVO);

        String content = updateCommentParamsVO.getContent();
        log.info("获取到用户修改的内容");
        checkContentIsSensitive(content);

        String taskId = updateCommentParamsVO.getTaskId();
        String publisher = updateCommentParamsVO.getPublisher();
        TaskPublishPO taskPublishPO = getAlreadyTaskById(taskId, publisher);
        String commentId = updateCommentParamsVO.getCommentId();
        checkTaskAndComment(taskId, username, taskPublishPO, commentId);

        updateComment(username, content, taskId, commentId);
    }

    @Override
    public PageResult<CommentDTO> getTaskCommentCache(PageParams pageParams, TaskCommentVO taskCommentVO) {
        log.info("获取到前端响应参数：{}", taskCommentVO);
        String taskId = taskCommentVO.getTaskId();
        log.info("获取到任务id：{}", taskId);
        String key = TASK_COMMENT_CACHE + taskId;
        String data = stringRedisTemplate.opsForValue().get(key);
        if (data != null) {
            return JSON.parseObject(data, new TypeReference<PageResult<CommentDTO>>() {
            });
        }

        String username = taskCommentVO.getUsername();
        log.info("获取到评论发布者：{}", username);
        RLock lock = redissonClient.getLock(TASK_QUERY_COMMENT_LOCK);
        lock.lock();

        try {
            Page<CommentPO> page = new Page<>(pageParams.getPageNo(), pageParams.getPageSize());

            LambdaQueryWrapper<CommentPO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(CommentPO::getUsername, username);
            queryWrapper.eq(CommentPO::getTaskId, taskId);

            Page<CommentPO> pageResult = commentMapper.selectPage(page, queryWrapper);
            log.info("获取到数据分页参数：{}", pageResult);
            List<CommentPO> records = pageResult.getRecords();
            log.info("获取到集合：{}", records);
            List<CommentDTO> commentDTOS = new ArrayList<>();
            for (CommentPO record : records) {
                log.info("获取到评论信息：{}", record);
                CommentDTO commentDTO = taskConverterParams.commentPO2CommentDTO(record);
                log.info("获取到转换后信息：{}", commentDTO);
                UserDTO userDTO = getUserDTO(record.getUsername());
                commentDTO.setUser(userDTO);
                commentDTOS.add(commentDTO);
            }
            log.info("获取到转换后参数：{}", commentDTOS);
            long total = pageResult.getTotal();

            PageResult<CommentDTO> result = new PageResult<>(commentDTOS, total,
                    pageParams.getPageNo(), pageParams.getPageSize());
            stringRedisTemplate.opsForValue().set(key, JSON.toJSONString(result), CACHE_TASK_QUEST_TTL, TimeUnit.SECONDS);
            return result;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public PageResult<CommentDTO> getTaskCommentAll(PageParams pageParams, CommentFilterParamsVO commentFilterParamsVO) {
        log.info("获取到前端响应信息：{}", commentFilterParamsVO);
        log.info("获取到分页参数：{}", pageParams);

        LambdaQueryWrapper<CommentPO> queryWrapper = new LambdaQueryWrapper<>();

        String commentId = commentFilterParamsVO.getCommentId();
        log.info("获取到评论表id：{}", commentId);
        queryWrapper.eq(commentId != null, CommentPO::getId, commentId);

        String content = commentFilterParamsVO.getContent();
        log.info("获取到评论内容：{}", content);
        queryWrapper.like(content != null, CommentPO::getContent, content);

        String username = commentFilterParamsVO.getUsername();
        log.info("获取到评论发布者名称：{}", username);
        queryWrapper.eq(username != null, CommentPO::getUsername, username);

        String taskId = commentFilterParamsVO.getTaskId();
        log.info("获取到任务id：{}", taskId);
        queryWrapper.eq(taskId != null, CommentPO::getTaskId, taskId);

        Page<CommentPO> page = new Page<>(pageParams.getPageNo(), pageParams.getPageSize());

        Page<CommentPO> pageResult = commentMapper.selectPage(page, queryWrapper);
        log.info("获取到数据分页参数：{}", pageResult);
        List<CommentPO> records = pageResult.getRecords();
        log.info("获取到集合：{}", records);
        List<CommentDTO> commentDTOS = new ArrayList<>();
        for (CommentPO record : records) {
            log.info("获取到评论信息：{}", record);
            CommentDTO commentDTO = taskConverterParams.commentPO2CommentDTO(record);
            log.info("获取到转换后信息：{}", commentDTO);
            UserDTO userDTO = getUserDTO(record.getUsername());
            commentDTO.setUser(userDTO);
            commentDTOS.add(commentDTO);
        }
        log.info("获取到转换后参数：{}", commentDTOS);
        long total = pageResult.getTotal();

        return new PageResult<>(commentDTOS, total, pageParams.getPageNo(), pageParams.getPageSize());

    }

    @Override
    @GlobalTransactional
    public void finishQuestTask(FinishQuestTaskVO finishTaskVO, String publisher) {
        log.info("获取到前端响应参数：{},publisher：{}", finishTaskVO, publisher);

        String taskId = finishTaskVO.getTaskId();
        log.info("获取到任务的id：{}", taskId);

        TaskPublishPO taskPublishPO = getAlreadyTaskById(taskId, publisher);
        log.info("获取到发布任务的信息：{}", taskPublishPO);

        String recipient = finishTaskVO.getRecipient();
        checkTaskTypeAndStatusQuest(taskId, taskPublishPO);

        log.info("开始修改任务状态");
        taskPublishPO.setOfflineDate(LocalDateTime.now());
        taskPublishPO.setStatus(TASK_FINISH);
        taskPublishPO.setRecipient(recipient);
        taskPublishPO.setReceiveTime(LocalDateTime.now());

        Integer star = finishTaskVO.getStar();
        log.info("获取到任务星级：{}", star);

        String publisherAppraise = finishTaskVO.getPublisherAppraise();
        log.info("获取到任务评论：{}", publisherAppraise);
        checkContentIsSensitive(publisherAppraise);

        log.info("插入任务评论表");
        insertTaskAppraise(taskPublishPO, star, publisherAppraise);

        log.info("将任务表与预发布表进行删除");
        deletePublishTask(taskId, publisher);

        TaskPublishPrePO taskPublishPrePO = getTaskById(taskId, publisher, false);
        if (taskPublishPrePO != null) {
            deletePreTask(taskId);
        }

        log.info("加入到历史表");
        insertTaskHistory(taskPublishPO);

        log.info("积分转账");
        rollBackCredit(recipient, taskPublishPO.getCredit());
        log.info("转账接收");

        updateUserStar(recipient);

        // 发送消息接受者任务已完成，发送消息接受者可以查看评论

        log.info("发布消息给任务接收者");
        String messageR = MESSAGE_HEAD + taskPublishPO.getTitle() + TASK_FINISH_NOTICE_RECEIVE_QUEST;
        receiveMessageToUser(messageR, recipient);

        log.info("发送消息给任务发布者");
        String messageP = MESSAGE_HEAD + taskPublishPO.getTitle() + TASK_FINISH_NOTICE_PUBLISH;
        receiveMessageToUser(messageP, publisher);
    }

    @Override
    public PageResult<TaskHistoryDTO> getTaskHistory(
            PageParams pageParams,
            TaskHistoryFilterParamsVO taskHistoryFilterParamsVO,
            String publisher,
            String recipient
    ) {
        log.info("获取到过滤参数：{}，发布者姓名：{}, 接受者姓名：{}", taskHistoryFilterParamsVO, publisher, recipient);
        LambdaQueryWrapper<TaskPublishHistoryPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(publisher != null, TaskPublishHistoryPO::getPublisher, publisher);
        queryWrapper.eq(recipient != null, TaskPublishHistoryPO::getRecipient, recipient);

        String title = taskHistoryFilterParamsVO.getTitle();
        log.info("获取到标题：{}", title);
        queryWrapper.like(title != null, TaskPublishHistoryPO::getTitle, title);

        String taskId = taskHistoryFilterParamsVO.getTaskId();
        log.info("获取到任务id：{}", taskId);
        queryWrapper.eq(taskId != null, TaskPublishHistoryPO::getId, taskId);

        String type = taskHistoryFilterParamsVO.getType();
        log.info("获取到任务类型：{}", type);
        queryWrapper.eq(type != null, TaskPublishHistoryPO::getType, type);

        Integer credit = taskHistoryFilterParamsVO.getCredit();
        log.info("获取到任务积分：{}", credit);
        queryWrapper.eq(credit != null, TaskPublishHistoryPO::getCredit, credit);

        Page<TaskPublishHistoryPO> page = new Page<>(pageParams.getPageNo(), pageParams.getPageSize());
        Page<TaskPublishHistoryPO> pageResult = taskPublishHistoryMapper.selectPage(page, queryWrapper);
        List<TaskPublishHistoryPO> records = pageResult.getRecords();
        List<TaskHistoryDTO> historyDTOS = new ArrayList<>();
        for (TaskPublishHistoryPO record : records) {
            TaskHistoryDTO historyDTO = taskConverterParams.taskPublishHistoryPO2TaskHistoryDTO(record);
            TaskAppraisePO taskAppraisePO = taskAppraiseMapper.selectOne(new LambdaQueryWrapper<TaskAppraisePO>()
                    .eq(publisher != null, TaskAppraisePO::getPublisher, publisher)
                    .eq(recipient != null, TaskAppraisePO::getRecipient, recipient)
                    .eq(TaskAppraisePO::getTaskId, record.getId())
            );
            UserDTO userDTO = getUserDTO(record.getPublisher());
            historyDTO.setPublisher(userDTO);
            historyDTO.setPublisherAppraise(taskAppraisePO.getPublisherAppraise());
            historyDTO.setStar(taskAppraisePO.getStar());
            historyDTOS.add(historyDTO);
        }
        long total = pageResult.getTotal();

        return new PageResult<>(historyDTOS, total, pageParams.getPageNo(), pageParams.getPageSize());
    }

    @Override
    public PageResult<TaskPublishDTO> queryAllAcceptedTask(PageParams pageParams, String recipient) {
        log.info("获取到响应参数：{}", pageParams);
        log.info("获取到接受者：{}", recipient);
        LambdaQueryWrapper<TaskPublishPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TaskPublishPO::getStatus, USER_TO_DO);
        queryWrapper.eq(TaskPublishPO::getRecipient, recipient);
        return getTaskPublishDTOPageResult(pageParams, queryWrapper, false);
    }

    @Override
    public PageResult<TaskPublishDTO> queryAllAcceptTask(PageParams pageParams, String publisher) {
        log.info("获取到用户名：{}", publisher);
        LambdaQueryWrapper<TaskPublishPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TaskPublishPO::getStatus, USER_TO_DO);
        queryWrapper.eq(TaskPublishPO::getPublisher, publisher);
        return getTaskPublishDTOPageResult(pageParams, queryWrapper, false);
    }

    private void insertTaskAppraise(TaskPublishPO taskPublishPO, Integer star, String publisherAppraise) {
        TaskAppraisePO taskAppraisePO = taskConverterParams.taskPublishPO2TaskAppraisePO(taskPublishPO);
        log.info("获取到任务完成评价表");
        taskAppraisePO.setPublisherAppraise(publisherAppraise);
        taskAppraisePO.setStar(star);
        log.info("获取到插入的数据");
        int insert = taskAppraiseMapper.insert(taskAppraisePO);
        if (insert <= 0) {
            log.error("插入任务评论表失败");
            throw new BizException(SQL_EX.getCode(), SQL_EX.getMsg() + "插入任务评论表失败");
        }
    }

    private void checkTaskTypeAndStatusQuest(String taskId, TaskPublishPO taskPublishPO) {
        String type = taskPublishPO.getType();
        log.info("获取到任务类型：{}", type);
        if (!QUESTIONS_AND_ANSWERS.equals(type)) {
            log.error("任务完成提交类型不正确");
            throw new BizException(SUBMITTED_TYPE_INCORRECT.getCode(),
                    SUBMITTED_TYPE_INCORRECT.getMsg() + "taskId：" + taskId + "非问答类型任务，无法提交");
        }

        String status = taskPublishPO.getStatus();
        log.info("获取到任务的状态：{}", status);
        if (USER_TO_DO.equals(status)) {
            log.error("任务完成提交状态不正确");
            throw new BizException(SUBMITTED_STATUS_INCORRECT.getCode(),
                    SUBMITTED_STATUS_INCORRECT.getMsg() + "taskId：" + taskId);
        }
    }

    private void updateComment(String username, String content, String taskId, String commentId) {
        CommentPO commentPO = new CommentPO();
        commentPO.setContent(content);
        int update = commentMapper.update(commentPO, new LambdaQueryWrapper<CommentPO>()
                .eq(CommentPO::getId, commentId)
                .eq(CommentPO::getUsername, username)
                .eq(CommentPO::getTaskId, taskId)
        );
        if (update <= 0) {
            log.error("更新用户评论表失败");
            throw new BizException(SQL_EX.getCode(), SQL_EX.getMsg() + "更新用户评论表失败");
        }
    }

    private void getCommentPO(String taskId, String username, String commentId) {
        log.info("获取到评论表id：{}", commentId);
        CommentPO commentPO = commentMapper.selectOne(new LambdaQueryWrapper<CommentPO>()
                .eq(commentId != null, CommentPO::getId, commentId)
                .eq(username != null, CommentPO::getUsername, username)
                .eq(taskId != null, CommentPO::getTaskId, taskId)
        );
        if (commentPO == null) {
            log.error("不存在的评论");
            throw new BizException(DATABASE_FIELD_DOES_NOT_EXIST.getCode(),
                    DATABASE_FIELD_DOES_NOT_EXIST.getMsg() + "不存在的评论");
        }
    }

    private void updateUserStar(String recipient) {
        int aveStar = (int) taskAppraiseMapper.polymerizationUserStar(recipient);
        log.info("获取到任务接受者评价平均评价星级：{}", aveStar);

        R<String> resultR = userServiceClient.updateUserStar(recipient, aveStar);
        if (!UPDATE_SUCCESS.equals(resultR.getMsg())) {
            log.error("远程调用出错更新用户星级");
            throw new BizException(resultR.getCode(), resultR.getMsg());
        }
    }

    private void updateTaskAppraise(String publisherAppraise, String publisher, String taskId, Integer star) {
        log.info("修改任务评价表");
        TaskAppraisePO taskAppraisePO = new TaskAppraisePO();
        taskAppraisePO.setStatus(TASK_FINISH);
        taskAppraisePO.setPublisherAppraise(publisherAppraise);
        taskAppraisePO.setStar(star);
        int update = taskAppraiseMapper.update(taskAppraisePO, new LambdaQueryWrapper<TaskAppraisePO>()
                .eq(TaskAppraisePO::getTaskId, taskId)
                .eq(TaskAppraisePO::getPublisher, publisher)
        );
        if (update <= 0) {
            log.error("更新任务评价表失败");
            throw new BizException(SQL_EX.getCode(), SQL_EX.getMsg() + " taskId：" + taskId);
        }
    }

    private void checkTaskTypeAndStatus(String taskId, TaskPublishPO taskPublishPO) {
        String type = taskPublishPO.getType();
        log.info("获取到任务类型：{}", type);
        if (QUESTIONS_AND_ANSWERS.equals(type)) {
            log.error("任务完成提交类型不正确");
            throw new BizException(SUBMITTED_TYPE_INCORRECT.getCode(),
                    SUBMITTED_TYPE_INCORRECT.getMsg() + "taskId：" + taskId);
        }

        String status = taskPublishPO.getStatus();
        log.info("获取到任务的状态：{}", status);
        if (PUBLISHED.equals(status)) {
            log.error("任务完成提交状态不正确");
            throw new BizException(SUBMITTED_STATUS_INCORRECT.getCode(),
                    SUBMITTED_STATUS_INCORRECT.getMsg() + "taskId：" + taskId);
        }

    }

    private TaskPublishPO getTaskPublishById(String taskId) {
        TaskPublishPO taskPublishPO = taskPublishMapper.selectOne(new LambdaQueryWrapper<TaskPublishPO>()
                .eq(TaskPublishPO::getId, taskId));
        if (taskPublishPO == null) {
            log.error("不存在这样的任务");
            throw new BizException(DATABASE_FIELD_DOES_NOT_EXIST.getCode(),
                    DATABASE_FIELD_DOES_NOT_EXIST.getMsg() + ": " + taskId);
        }
        return taskPublishPO;
    }

    @NotNull
    private PageResult<TaskPublishDTO> getTaskPublishDTOPageResult(PageParams pageParams,
                                                                   LambdaQueryWrapper<TaskPublishPO> queryWrapper, boolean isCache) {
        Page<TaskPublishPO> page = new Page<>(pageParams.getPageNo(), pageParams.getPageSize());
        Page<TaskPublishPO> pageResult = taskPublishMapper.selectPage(page, queryWrapper);
        log.info("获取到分页结果：{}", pageResult);
        List<TaskPublishPO> records = pageResult.getRecords();
        List<TaskPublishDTO> taskPublishDTOS = new ArrayList<>();
        for (TaskPublishPO record : records) {
            log.info("获取到每一条记录信息：{}", record);
            String publisher = record.getPublisher();
            UserDTO data = getUserDTO(publisher);
            TaskPublishDTO taskPublishDTO = taskConverterParams.taskPublishPO2TaskPublishDTO(record);
            log.info("获取到转换之后的任务信息：{}", taskPublishDTO);
            taskPublishDTO.setPublisher(data);
            if (QUESTIONS_AND_ANSWERS.equals(record.getType())) {
                List<CommentPO> commentPOList = commentMapper.selectList(new LambdaQueryWrapper<CommentPO>()
                        .eq(CommentPO::getTaskId, record.getId())
                );
                if (CollectionUtils.isNotEmpty(commentPOList)) {
                    List<CommentDTO> list = taskConverterParams.commentPO2CommentDTOList(commentPOList);
                    taskPublishDTO.setCommentDTOS(list);
                }
            }
            taskPublishDTOS.add(taskPublishDTO);
        }
        long total = pageResult.getTotal();
        log.info("获取到总条数：{}", total);
        PageResult<TaskPublishDTO> result = new PageResult<>(taskPublishDTOS, total, pageParams.getPageNo(), pageParams.getPageSize());
        if (isCache) {
            stringRedisTemplate.opsForValue().set(PUBLISH_TASK_CACHE, JSON.toJSONString(result), CACHE_TASK_TTL, TimeUnit.SECONDS);
        }
        return result;
    }

    private UserDTO getUserDTO(String publisher) {
        log.info("获取到发布者id：{}", publisher);
        String key = USER_PREFIX + publisher;
        String user = stringRedisTemplate.opsForValue().get(key);
        if (StringUtils.isNotBlank(user)) {
            return JSON.parseObject(user, UserDTO.class);
        }
        R<UserRemote> publishMessage = userServiceClient.getPublishMessage(publisher);

        if (!publishMessage.getMsg().equals(R.QUERY_WAS_SUCCESSFUL)) {
            throw new BizException(publishMessage.getCode(), publishMessage.getMsg());
        }
        UserRemote dataR = publishMessage.getData();
        UserDTO data = taskConverterParams.userRemote2UserDTO(dataR);
        stringRedisTemplate.opsForValue().set(key, JSON.toJSONString(data), 8, TimeUnit.HOURS);
        log.info("获取到转换的用户数据：{}", data);
        return data;
    }

    @Override
    @GlobalTransactional
    public PageResult<TaskPublishDTO> queryAllTaskByOrder(PageParams pageParams, TaskOrderParamsVO taskOrderParamsVO) {
        log.info("获取到分页参数：{}", pageParams);
        log.info("获取到排序字段：{}", taskOrderParamsVO);
        LambdaQueryWrapper<TaskPublishPO> queryWrapper = new LambdaQueryWrapper<>();


        boolean credit = BooleanUtils.isTrue(taskOrderParamsVO.getCredit());
        log.info("获取到积分：{}", credit);
        queryWrapper.orderByAsc(credit, TaskPublishPO::getCredit);

        boolean publishTime = BooleanUtils.isTrue(taskOrderParamsVO.getPublishTime());
        log.info("获取到发布时间：{}", publishTime);
        queryWrapper.orderByAsc(publishTime, TaskPublishPO::getPublishTime);

        boolean taskStartTime = BooleanUtils.isTrue(taskOrderParamsVO.getTaskStartTime());
        log.info("获取到任务开始时间：{}", taskStartTime);
        queryWrapper.orderByAsc(taskStartTime, TaskPublishPO::getTaskStartTime);

        boolean taskEndTime = BooleanUtils.isTrue(taskOrderParamsVO.getTaskEndTime());
        log.info("获取到任务结束时间：{}", taskEndTime);
        queryWrapper.orderByAsc(taskEndTime, TaskPublishPO::getTaskEndTime);


        return getTaskPublishDTOPageResult(pageParams, queryWrapper, false);
    }

    @Override
    @GlobalTransactional
    public void scheduledDeleteExpireTask() {
        List<TaskPublishPO> taskPublishPOList = taskPublishMapper.selectList(null);
        LocalDateTime now = LocalDateTime.now();
        log.info("获取现在的时间：{}", now);
        for (TaskPublishPO taskPublishPO : taskPublishPOList) {
            log.info("问答任务放行");
            if (QUESTIONS_AND_ANSWERS.equals(taskPublishPO.getType()) &&
                    PUBLISHED.equals(taskPublishPO.getStatus())) {
                return;
            }

            LocalDateTime taskEndTime = taskPublishPO.getTaskEndTime();
            log.info("获取到任务结束时间：{}", taskEndTime);
            String recipient = taskPublishPO.getRecipient();
            log.info("获取到接受者id：{}", recipient);
            String publisher = taskPublishPO.getPublisher();
            if (now.isAfter(taskEndTime) && StringUtils.isBlank(recipient)) {
                log.info("开始移动到历史表");
                TaskParamsVO paramsVO = new TaskParamsVO();
                paramsVO.setTaskId(taskPublishPO.getId().toString());
                paramsVO.setPublisher(publisher);
                log.info("获取到参数：{}", paramsVO);
                taskPublish.revokeTask(paramsVO);
                log.info("删除任务结束");
                taskPublishPO.setStatus(StringConstant.TASK_EXPIRE);
                // 设置下架时间
                taskPublishPO.setOfflineDate(LocalDateTime.now());
                insertTaskHistory(taskPublishPO);
            }
            log.info("更新状态为未完成，交给用户来决定是否任务继续");
            TaskPublishPO taskPublishPOUpdate = new TaskPublishPO();
            taskPublishPOUpdate.setStatus(StringConstant.TASK_INCOMPLETE);
            int update = taskPublishMapper.update(taskPublishPOUpdate, new LambdaQueryWrapper<TaskPublishPO>()
                    .eq(TaskPublishPO::getId, taskPublishPO.getId()));
            if (update <= 0) {
                log.error("更新任务发布表失败");
                throw new BizException(ExceptionCode.INTERNAL_SERVER_ERROR.getCode(),
                        "更新任务发布表失败taskId：" + taskPublishPO.getId());
            }

            log.info("开始发布通过给用户：{}", publisher);
            String message = TASK_TIME_OUT + "任务标题：" + taskPublishPO.getTitle();

            receiveMessageToUser(message, publisher);
        }
    }

    @Override
    @Transactional
    public void acceptAssignment(AcceptTaskParamsVO acceptTaskParamsVO) {
        log.info("获取到前端响应参数：{}", acceptTaskParamsVO);

        String recipient = acceptTaskParamsVO.getRecipient();
        log.info("获取到接收人id：{}", recipient);
        String taskId = acceptTaskParamsVO.getTaskId();
        log.info("获取到任务id：{}", taskId);
        String publisher = acceptTaskParamsVO.getPublisher();
        log.info("获取到发布者：{}", publisher);

        if (publisher.equals(recipient)) {
            log.error("错误任务接收，不能自己接收自己发布的任务");
            throw new BizException(INCORRECT_RECEPTION.getCode(), INCORRECT_RECEPTION.getMsg());
        }

        TaskPublishPO taskPublishPO = checkTaskIsAccept(taskId, publisher);

        Integer count = taskPublishMapper.selectCount(new LambdaQueryWrapper<TaskPublishPO>()
                .eq(TaskPublishPO::getRecipient, recipient)
        );

        if (count >= 3) {
            log.error("任务数太多了，请先完成任务");
            throw new BizException(TOO_MANY_TASKS.getCode(), TOO_MANY_TASKS.getMsg());
        }

        if (QUESTIONS_AND_ANSWERS.equals(taskPublishPO.getType())) {
            log.error("问答互助不能单人接收任务");
            throw new BizException(ExceptionCode.ANSWERS.getCode(),
                    ExceptionCode.ANSWERS.getMsg() + "。taskId" + taskId);
        }

        LocalDateTime now = checkTaskTimeIsAvailable(taskPublishPO);

        RLock lock = redissonClient.getLock(RedisConstant.TASK_RECEIVE_REDISSON_LOCK);
        log.info("获取到锁：{}", lock);

        log.info("开始加锁");
        lock.lock();

        checkTaskIsAccept(taskId, publisher);

        try {
            TaskPublishPO taskPublishPOUpdate = new TaskPublishPO();
            taskPublishPOUpdate.setStatus(USER_TO_DO);
            taskPublishPOUpdate.setRecipient(recipient);
            taskPublishPOUpdate.setReceiveTime(now);

            int update = taskPublishMapper.update(taskPublishPOUpdate, new LambdaQueryWrapper<TaskPublishPO>()
                    .eq(TaskPublishPO::getId, taskId)
                    .eq(TaskPublishPO::getPublisher, publisher));
            if (update <= 0) {
                log.info("更新任务发布表失败");
                throw new BizException(ExceptionCode.INTERNAL_SERVER_ERROR.getCode(),
                        "更新任务发布表失败taskId：" + taskPublishPO.getId());
            }
        } finally {
            lock.unlock();
        }

        TaskAppraisePO taskAppraisePO = taskAppraiseMapper.selectOne(new LambdaQueryWrapper<TaskAppraisePO>()
                .eq(TaskAppraisePO::getTaskId, taskId)
                .eq(TaskAppraisePO::getPublisher, publisher)
                .eq(TaskAppraisePO::getRecipient, recipient));
        if (taskAppraisePO != null) {
            log.error("插入评价表失败，评价表已经存在");
            throw new BizException(ExceptionCode.INTERNAL_SERVER_ERROR.getCode(), "评价表已存在，请勿重复添加");
        }

        TaskPublishPO publishPO = getAlreadyTaskById(taskId, publisher);
        log.info("获取到转换前参数：{}", publishPO);
        TaskAppraisePO taskAppraisePOInsert = taskConverterParams.taskPublishPO2TaskAppraisePO(publishPO);
        log.info("获取到转换后参数：{}", taskAppraisePOInsert);

        int insert = taskAppraiseMapper.insert(taskAppraisePOInsert);
        if (insert <= 0) {
            log.error("插入评价表失败");
            throw new BizException(ExceptionCode.INTERNAL_SERVER_ERROR.getCode(), "插入评论表失败。taskId：" + taskId);
        }

        String message = "您发布的任务：" + publishPO.getTitle() + "已经被其他用户所接收，请及时进行处理";

        receiveMessageToUser(message, publisher);

    }

    @NotNull
    private TaskPublishPO checkTaskIsAccept(String taskId, String publishId) {
        TaskPublishPO taskPublishPO = getAlreadyTaskById(taskId, publishId);
        log.info("获取到发布表信息：{}", taskPublishPO);

        String recipientDB = taskPublishPO.getRecipient();
        if (StringUtils.isNotBlank(recipientDB)) {
            log.error("任务已经被其他用户接收了");
            throw new BizException(ExceptionCode.RECEIVED.getCode(),
                    ExceptionCode.RECEIVED.getMsg() + "。taskId：" + taskId);
        }
        return taskPublishPO;
    }

    @NotNull
    private static LocalDateTime checkTaskTimeIsAvailable(TaskPublishPO taskPublishPO) {
        LocalDateTime now = LocalDateTime.now();
        log.info("获取到现在的时间：{}", now);

        LocalDateTime taskStartTime = taskPublishPO.getTaskStartTime();
        log.info("获取到任务开始时间：{}", taskStartTime);

        if (now.isBefore(taskStartTime)) {
            log.error("任务还没有开始");
            throw new BizException(ExceptionCode.NOT_START.getCode(), ExceptionCode.NOT_START.getMsg());
        }

        LocalDateTime taskEndTime = taskPublishPO.getTaskEndTime();
        log.info("获取到任务结束时间：{}", taskEndTime);

        if (now.isAfter(taskEndTime)) {
            log.error("任务已经结束了");
            throw new BizException(ExceptionCode.ENDED.getCode(), ExceptionCode.ENDED.getMsg());
        }
        return now;
    }


    private void insertTaskHistory(TaskPublishPO taskPublishPO) {
        checkTaskHistoryIsExist(taskPublishPO);
        TaskPublishHistoryPO historyPO = taskConverterParams.taskPublishPO2TaskPublishHistoryPO(taskPublishPO);
        log.info("获取到转换后信息：{}", historyPO);
        int insert = taskPublishHistoryMapper.insert(historyPO);
        if (insert <= 0) {
            log.error("插入历史表失败");
            throw BizException.wrap(SQL_EX.getCode(), SQL_EX.getMsg() + "：插入历史表失败。taskId：" + taskPublishPO.getId());
        }
    }

    private void checkTaskHistoryIsExist(TaskPublishPO taskPublishPO) {
        log.info("开始校验历史表中是否存在该记录");
        TaskPublishHistoryPO taskPublishHistoryPO = taskPublishHistoryMapper.selectOne(new LambdaQueryWrapper<TaskPublishHistoryPO>()
                .eq(TaskPublishHistoryPO::getId, taskPublishPO.getId())
                .eq(TaskPublishHistoryPO::getPublisher, taskPublishPO.getPublisher()));
        if (taskPublishHistoryPO != null) {
            log.error("重复的插入");
            throw new BizException(REPEAT_ADDITION.getCode(), REPEAT_ADDITION.getMsg() + "。taskId：" + taskPublishHistoryPO.getId());
        }
    }

    private TaskPublishHistoryPO getTaskHistory(String taskId, String publishId) {
        TaskPublishHistoryPO taskPublishHistoryPO = taskPublishHistoryMapper.selectOne(new LambdaQueryWrapper<TaskPublishHistoryPO>()
                .eq(TaskPublishHistoryPO::getId, taskId)
                .eq(TaskPublishHistoryPO::getPublisher, publishId));
        if (taskPublishHistoryPO == null) {
            log.error("不存在这样的历史任务");
            throw new BizException(DATABASE_FIELD_DOES_NOT_EXIST.getCode(),
                    DATABASE_FIELD_DOES_NOT_EXIST.getMsg() + ": " + taskId);
        }
        return taskPublishHistoryPO;
    }


    private TaskAppraisePO getAppraiseTask(String taskId, String publisher) {
        TaskAppraisePO taskAppraisePO = taskAppraiseMapper.selectOne(new LambdaQueryWrapper<TaskAppraisePO>()
                .eq(TaskAppraisePO::getTaskId, taskId)
                .eq(TaskAppraisePO::getPublisher, publisher));
        if (taskAppraisePO == null) {
            log.error("不存在这样的任务完成评价表信息");
            throw new BizException(DATABASE_FIELD_DOES_NOT_EXIST.getCode(),
                    DATABASE_FIELD_DOES_NOT_EXIST.getMsg() + ": " + taskId);
        }
        return taskAppraisePO;
    }

    private TaskPublishPO getAlreadyTaskById(String taskId, String publisher) {
        TaskPublishPO taskPublishPO = taskPublishMapper.selectOne(new LambdaQueryWrapper<TaskPublishPO>()
                .eq(TaskPublishPO::getId, taskId)
                .eq(publisher != null, TaskPublishPO::getPublisher, publisher)
        );
        if (taskPublishPO == null) {
            log.error("不存在这样的任务");
            throw new BizException(DATABASE_FIELD_DOES_NOT_EXIST.getCode(),
                    DATABASE_FIELD_DOES_NOT_EXIST.getMsg() + ": " + taskId);
        }
        return taskPublishPO;
    }

    private void rollBackCredit(String publisher, Integer credit) {
        if (credit <= 0) {
            return;
        }

        R<String> rollbackCredit = userServiceClient.rollbackCredit(publisher, credit);
        if (!rollbackCredit.getMsg().equals(UPDATE_SUCCESS)) {
            log.info("回滚用户积分失败");
            throw new BizException(ExceptionCode.ROLL_BACK_CREDIT_FALSE.getCode(),
                    ExceptionCode.ROLL_BACK_CREDIT_FALSE.getMsg());
        }
    }

    @Override
    @Transactional
    public void auditPreTask(TaskAuditPO taskAuditPO) {

        log.info("获取到前端响应参数：{}", taskAuditPO);

        // 1. 判断在审核期任务是否下架并且是未审核
        TaskPublishPrePO taskPublishPrePO = checkTaskPrePublishIsCheck(taskAuditPO.getTaskId().toString());
        log.info("获取到预发布信息：{}", taskPublishPrePO);

        LambdaQueryWrapper<TaskPublishPO> queryWrapper = new LambdaQueryWrapper<TaskPublishPO>()
                .eq(TaskPublishPO::getId, taskPublishPrePO.getId());
        TaskPublishPO taskPublishPODB = taskPublishMapper.selectOne(queryWrapper);
        log.info("获取到数据库数据：{}", taskPublishPODB);

        if (taskPublishPODB != null && USER_TO_DO.equals(taskPublishPODB.getStatus())) {
            taskAuditPO.setAuditMind("当前任务已经发布并且被其他的用户所接收，您不能再进行修改");
            taskAuditPO.setAuditStatus(AUDIT_FALSE);
        }

        // 3. 插入数据库
        // 3.1 先检查是否存在，存在就进行更新，不存在在进行插入
        insertTaskAudit(taskAuditPO);

        // 5. 审核失败：
        String publisher = taskPublishPrePO.getPublisher();
        if (AUDIT_FALSE.equals(taskAuditPO.getAuditStatus())) {
            log.info("审核失败");
            taskPublishPrePO.setStatus(AUDIT_FALSE);
            int update = taskPublishPreMapper.updateById(taskPublishPrePO);
            if (update <= 0) {
                log.error("修改预发布表状态失败");
                throw BizException.wrap(ExceptionCode.SQL_EX.getCode(),
                        ExceptionCode.SQL_EX.getMsg() + "：修改预发布表状态失败");
            }
            // 5.1 发送消息
            log.info("开始发送消息");
            String message = "您的任务：" + taskPublishPrePO.getTitle() + "审核失败。" + "请遵循管理员意见进行修改：" + taskAuditPO.getAuditMind();
            receiveMessageToUser(message, publisher);
            return;
        }


        // 4. 审核成功，
        // 4.1 将预发布表状态改为已审核，
        log.info("审核成功");
        taskPublishPrePO.setStatus(StringConstant.PUBLISHED);
        int update = taskPublishPreMapper.updateById(taskPublishPrePO);
        if (update <= 0) {
            log.error("修改预发布表状态失败");
            throw BizException.wrap(ExceptionCode.SQL_EX.getCode(),
                    ExceptionCode.SQL_EX.getMsg() + "：修改预发布表状态失败");
        }

        // 4.2 复制到发布表并且插入或者更新
        insertOrUpdatePublishTask(taskPublishPrePO, taskPublishPODB);

        log.info("开始发送消息");
        String message = taskPublishPrePO.getTitle() + MqConstant.AUDIT_SUCCESS;
        receiveMessageToUser(message, publisher);

    }

    private void insertOrUpdatePublishTask(TaskPublishPrePO taskPublishPrePO, TaskPublishPO taskPublishPODB) {
        TaskPublishPO taskPublishPO = taskConverterParams.taskPublishPrePO2TaskPublishPO(taskPublishPrePO);
        log.info("获取到转换后参数：{}", taskPublishPO);
        if (taskPublishPODB != null) {
            // 更新
            log.info("更新");
            int updateById = taskPublishMapper.updateById(taskPublishPO);
            if (updateById <= 0) {
                log.error("更新发布表失败");
                throw BizException.wrap(ExceptionCode.SQL_EX.getCode(),
                        ExceptionCode.SQL_EX.getMsg() + "：更新发布表失败");
            }
        } else {
            log.info("插入");
            int insertPublish = taskPublishMapper.insert(taskPublishPO);
            if (insertPublish <= 0) {
                log.error("添加发布表失败");
                throw BizException.wrap(ExceptionCode.SQL_EX.getCode(),
                        ExceptionCode.SQL_EX.getMsg() + "：添加发布表失败");
            }
        }
    }

    private void insertTaskAudit(TaskAuditPO taskAuditPO) {
        int insert = taskAuditMapper.insert(taskAuditPO);
        log.info("获取到插入条数：{}", insert);
        if (insert <= 0) {
            log.error("插入审核数据失败");
            throw BizException.wrap(ExceptionCode.SQL_EX.getCode(),
                    ExceptionCode.SQL_EX.getMsg() + "：插入审核数据失败");
        }
    }


    @NotNull
    private TaskPublishPrePO checkTaskPrePublishIsCheck(String taskId) {
        TaskPublishPrePO taskPublishPrePO = taskPublishPreMapper.selectOne(new LambdaQueryWrapper<TaskPublishPrePO>()
                .eq(TaskPublishPrePO::getId, taskId));
        if (taskPublishPrePO == null) {
            log.error("不存在这样的任务");
            throw new BizException(DATABASE_FIELD_DOES_NOT_EXIST.getCode(),
                    DATABASE_FIELD_DOES_NOT_EXIST.getMsg());
        }
        String status = taskPublishPrePO.getStatus();
        if (PUBLISHED.equals(status)) {
            log.error("该任务已经审核过了，请勿重复审核");
            throw new BizException(REPEAT_AUDIT.getCode(), REPEAT_AUDIT.getMsg());
        }

        if (AUDIT_FALSE.equals(status)) {
            log.error("这不是可以审核的任务类型");
            throw new BizException(INTERNAL_SERVER_ERROR.getCode(), "任务不是可以审核的状态，请修改或者重新编辑之后在进行审核");
        }
        return taskPublishPrePO;
    }


    private TaskPublishPrePO getTaskById(String taskId, String publisher, boolean isNecessaryCheck) {
        TaskPublishPrePO taskPublishPrePO = taskPublishPreMapper.selectOne(new LambdaQueryWrapper<TaskPublishPrePO>()
                .eq(TaskPublishPrePO::getId, taskId)
                .eq(TaskPublishPrePO::getPublisher, publisher));
        if (isNecessaryCheck) {
            if (taskPublishPrePO == null) {
                log.error("不存在这样的任务");
                throw new BizException(DATABASE_FIELD_DOES_NOT_EXIST.getCode(),
                        DATABASE_FIELD_DOES_NOT_EXIST.getMsg() + ": " + taskId);
            }
        }
        return taskPublishPrePO;
    }


    private void checkTaskIsExisted(String title, String content, String publisher) {
        Integer count = taskPublishPreMapper.selectCount(new LambdaQueryWrapper<TaskPublishPrePO>()
                .eq(TaskPublishPrePO::getTitle, title)
                .eq(TaskPublishPrePO::getContent, content)
                .eq(TaskPublishPrePO::getPublisher, publisher)
        );

        if (count > 0) {
            log.error("重复添加的任务");
            throw new BizException(REPEAT_ADDITION.getCode(), REPEAT_ADDITION.getMsg() + " title: " + title);
        }
    }

    private void createPreTask(CreateTaskParamsVO createTaskParamsVO, String publisher) {
        // 发布任务
        log.info("获取到前端响应信息：{}， 当前登录用户为：{}", createTaskParamsVO, publisher);
        TaskPublishPrePO publishPrePO = taskConverterParams.createTaskParamsVO2TaskPublishPrePO(createTaskParamsVO);
        log.info("获取到转换信息：{}", publishPrePO);
        publishPrePO.setPublisher(publisher);
        publishPrePO.setType("00400" + publishPrePO.getType());
        int insert = taskPublishPreMapper.insert(publishPrePO);
        if (insert <= 0) {
            log.error("发布任务失败");
            throw BizException.wrap(ExceptionCode.SQL_EX.getCode(),
                    ExceptionCode.SQL_EX.getMsg() + "发布任务失败");
        }
    }

    private void sendMessageToUser(Object message) {
        // 1.全局唯一的消息ID，需要封装到CorrelationData中
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        // 2.添加callback，这里的getFuture()获取将来的消息，对将来的处理和封装
        correlationData.getFuture().addCallback(
                result -> {
                    assert result != null;
                    if (result.isAck()) {
                        // 3.1.ack，消息成功
                        log.info("消息发送成功, ID:{}", correlationData.getId());
                    } else {
                        // 3.2.nack，消息失败
                        log.error("消息发送失败, ID:{}, 原因{}", correlationData.getId(), result.getReason());
                    }
                },
                ex -> log.error("消息发送异常, ID:{}, 原因{}", correlationData.getId(), ex.getMessage())
        );

        rabbitTemplate.convertAndSend(MqConstant.USER_EXCHANGE, "", message, correlationData);
    }


}
